#include <cassert>
#include <iostream>
using namespace std;

#include "DyeFieldRender.h"
#include "FlowSimUtil.h"

using namespace FlowSim;
using namespace Ogre;

DyeFieldRender::DyeFieldRender(SceneManager* scnMgr):_scnMgr(scnMgr),_df(0),_dfNode(0),
						     _dij(1),_texture(0)
{
  
}

void DyeFieldRender::refresh(DyeField3* df)
{
  _df = df;
  update();
}

void DyeFieldRender::setInput(DyeField3* df)
{
  _df = df;
  if(_dfNode != 0)
    {
      _scnMgr->getRootSceneNode()->removeAndDestroyChild("DyeField");
      _dfNode = 0;
    }
  _dfNode = _scnMgr->getRootSceneNode()->createChildSceneNode("DyeField");
  setupRender();
}

void DyeFieldRender::setupRender()
{
  
  _texture = TextureManager::getSingleton().createManual(
							 "DyeTexture", // name
							 ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
							 TEX_TYPE_2D,      // type
							 _df->getSize(),_df->getSize(),         // width & height
							 0,                // number of mipmaps
							 PF_BYTE_BGRA,     // pixel format
							 TU_DYNAMIC_WRITE_ONLY_DISCARDABLE);      // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for
  // textures updated very often (e.g. each frame)
  update();
  // Create a material using the texture
  MaterialPtr material = MaterialManager::getSingleton().create(
								"DyeTextureMaterial", // name
								ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

  material->getTechnique(0)->getPass(0)->createTextureUnitState("DyeTexture");
  material->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA);
  //setup the plane
  Plane plane(Vector3::UNIT_Z,0);
  int size = _df->getSize();
  MeshManager::getSingleton().createPlane("dyefield",
					  ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane,
					  size,size,1,1,true,1,1,1,Vector3::UNIT_Y);
  Entity* ent = _scnMgr->createEntity("DyeFieldEntity","dyefield");
  _dfNode->attachObject(ent);
  _dfNode->setPosition(size/2,size/2,0.0);
  ent->setMaterialName("DyeTextureMaterial");
  ent->setCastShadows(false);

}

void DyeFieldRender::update()
{
  // Get the pixel buffer
  HardwarePixelBufferSharedPtr pixelBuffer = _texture->getBuffer();

  // Lock the pixel buffer and get a pixel box
  pixelBuffer->lock(HardwareBuffer::HBL_DISCARD); // for best performance use HBL_DISCARD!
  const PixelBox& pixelBox = pixelBuffer->getCurrentLock();

  uint8* pDest = static_cast<uint8*>(pixelBox.data);

  // Fill in some pixel data. This will give a semi-transparent blue,
  // but this is of course dependent on the chosen pixel format.
  int size = _df->getSize();
  Real* rd = _df->getRData();
  Real* gd = _df->getGData();
  Real* bd = _df->getBData();
  Real tr;
  Real tg;
  Real tb;
  for (size_t i = 0; i < size; i++)
    for(size_t j = 0; j < size; j++)
      {
	*pDest++ = bd[A_INDEX(j,((size-1)-i),size)]*255; // B
        *pDest++ = gd[A_INDEX(j,((size-1)-i),size)]*255; // G
        *pDest++ = rd[A_INDEX(j,((size-1)-i),size)]*255; // R
	*pDest++ = 255;
      }
  // Unlock the pixel buffer
  pixelBuffer->unlock();
}


